package com.google.code.mochaccino.framework.guice.module;
/**
 * Copyright 2012 Claude Houle claude.houle@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.PrivateBinder;
import com.google.inject.PrivateModule;
import com.google.inject.multibindings.Multibinder;

/**
 * The Set Binder Private Module allows to expose in a set-binder a series of
 * private-module classes. However, note that this class will not respect JSR250
 * contracts regarding PreDestroy and PostConstruct annotations for non-set-binded types.
 * <p/>
 * If the bean is not exposed in a set, it is not a valid declaration regarding JSR250.
 */
public abstract class MultiBinderPrivateModule extends AbstractModule {

	private Class[]  types;
	private Injector injector;

	public MultiBinderPrivateModule( Class[] types ) {
		this.types = types;
	}

	public MultiBinderPrivateModule( Class type ) {
		this.types = new Class[] { type };
	}

	@Override
	protected final void configure() {
		injector = Guice.createInjector( getPrivateModule() );
		for ( Class<?> type : types ) {
			Multibinder<Object> mapBinder = (Multibinder<Object>) Multibinder.newSetBinder( binder(), type );
			Object value = injector.getInstance( type );
			mapBinder.addBinding().toInstance( value );
		}
	}

	public final PrivateModule getPrivateModule() {
		return new PrivateModule() {
			@Override
			protected void configure() {
				configureModule( binder() );
				for ( Class type : types ) {
					expose( type );
				}
			}
		};
	}

	protected abstract void configureModule( PrivateBinder binder );
}
